home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ9005.ZIP
/
MOESER.LST
< prev
next >
Wrap
File List
|
1990-03-23
|
13KB
|
514 lines
_A MEMORY CONTROLLER_
by Robert A. Moeser
[LISTING ONE]
.
.
.
typedef struct {
int anInt;
long aLong;
char tenChars[10]; /* details are unimportant */
} Thing;
typedef union utag {
Thing aThing;
union utag *next;
} freeList;
.
.
.
freeList *freeThings = 0; /* free list, empty to begin */
Thing *newThing() /* new or recycled Thing */
{
Thing *t;
if (freeThings) { /* any on free list? */
t = (Thing *) freeThings;
freeThings = freeThings->next;
}
else /* no, go malloc one */
t = (Thing *) malloc(sizeof *t);
return (t);
}
void freeThing(theThing) /* put Thing on freeList */
Thing *theThing;
{
((freeList *) theThing)->next = freeThings;
freeThings = (freeList *) theThing;
}
[LISTING TWO]
/* Header for memory control package
C 1989 Robert A. Moeser, all rights reserved */
/* some things probably in your standard headers... */
#ifndef __size_t
#define __size_t
typedef unsigned long size_t;
#endif
void *malloc(size_t);
void free(void *);
int printf(char *, ...);
int sprintf(char *, char *, ...);
int scanf(char *, ...);
int rand(void);
/* end of things probably in your standard headers... */
typedef long counter; /* a bit excessive, perhaps... */
typedef struct _mc {
struct _mc *next; /* used for doubly-linked list */
struct _mc *prev; /* of all mcs */
size_t itemSize; /* the size of the object this MCon controls */
void *freeList; /* a free list of objects */
counter nGiven; /* number of items handed out */
counter nOut; /* number still out there somewhere */
counter nFree; /* length of free list */
} *MCon;
MCon newMCon(size_t theItemSize); /* 0 = could not get storage */
void *newInstanceOf(MCon theCon); /* 0 = could not get storage */
void disposeInstance(void *theItem);
void purgeMCon(MCon theCon);
counter disposeMCon(MCon theCon); /* number of orphans created by action */
void purgeAllMCons(void);
counter disposeAllMCons(void); /* number of orphans created by action */
[LISTING THREE]
/* A Memory Controller. C 1989 Robert A. Moeser, all rights reserved */
# include "mem.h"
static void linkIn(MCon theCon);
static void linkOut(MCon theCon);
static int initMControl(void);
void debugCon(char *);
void printCon(MCon theCon);
static MCon controlCon = 0; /* 0 -> not yet initialized */
/* Initialize the memory control "package." Returns 1 for successful
initialization or already initialized; returns 0 if it fails. Called
automatically by newMCon, but you can call it explicity if you like. */
int initMControl(void)
{
if (controlCon) return (1); /* already initialized! */
controlCon = (MCon) malloc(sizeof *controlCon);
if (!controlCon) return (0); /* sad but true! */
controlCon->itemSize = sizeof *controlCon;
controlCon->nGiven = controlCon->nOut = controlCon->nFree = 0;
controlCon->freeList = (void *) 0;
controlCon->next = controlCon->prev = controlCon;
return (1); /* OK! */
}
/* Register a new type (object) for management by the memory controller
takes size of the object as an argument and returns an MCon object, which
is zero in case of failure. The Mcon object is used later to manage creation
of all instances of the new object, to maintain a free list for the object
and to keep track of demand for the object */
MCon newMCon(size_t theItemSize)
{
MCon t;
int k;
k = initMControl();
if (!k) return ((void *) 0);
t = newInstanceOf(controlCon);
if (!t) return ((void *) 0);
t->itemSize = theItemSize;
t->nGiven = t->nOut = t->nFree = 0;
t->freeList = (void *) 0;
linkIn(t);
return (t);
}
/* Create a new object. Takes the object's MCon as an argument (previously
created by newMCon). Returns a pointer to a new instance of the object */
void *newInstanceOf(MCon theCon)
{
void *t;
if (theCon->freeList) { /* any on free list? */
t = theCon->freeList;
theCon->freeList = *((MCon *) t);
theCon->nFree--;
}
else /* nope, go malloc one */
t = malloc(theCon->itemSize + (sizeof theCon));
if (!t) return ((void *) 0); /* allocator failure... */
*((MCon *) t) = theCon; /* remember the controller */
theCon->nGiven++;
theCon->nOut++;
return ((void *) ((MCon *) t + 1));
}
/* Dispose of an object. Takes a pointer to the object to dispose of
the storage is kept by the object's MCon on a free list for reuse. */
void disposeInstance(void *theItem)
{
MCon t;
void *x;
int g;
t = *((MCon *) theItem - 1); /* recover controllor */
t->nOut--;
t->nFree++;
*((MCon *) theItem - 1) = t->freeList;
t->freeList = (MCon *) theItem - 1;
}
/* Purge the free list for an MCon. Takes the MCon whose free list should be
returned to the system storage allocator */
void purgeMCon(MCon theCon)
{
void *bop, *bop2;
bop = theCon->freeList;
while (bop) {
bop2 = *((void **) bop);
free(bop);
bop = bop2;
}
theCon->freeList = (void *) 0;
theCon->nFree = 0;
}
/* Unregister a type. Takes the MCon object that is no longer needed
returns the number of "orphans" created. Since active instances are entirely
the responsibility of clients of the memory control package, disposing of
an MCon can mean that there may be outstanding objects of the
no-longer-existing type. This is not strictly an error, but since there is
now no way to free the storage used by the orphans should be a warning sign. */
counter disposeMCon(MCon theCon)
{
counter orphans = 0; /* did this dispose create "orphans" ? */
orphans = theCon->nOut;
purgeMCon(theCon); /* goodbye the free list */
linkOut(theCon);
disposeInstance((void *) theCon);
return (orphans); /* number of "orphans", should be 0! */
}
/* Purge the free list of every object type known to the memory controller
a client might call this in a desperate attempt to satisfy a memory request */
void purgeAllMCons(void)
{
MCon bop;
bop = controlCon;
do {
purgeMCon(bop);
bop = bop->next;
} while (bop != controlCon);
}
/* Unregister all types. This action can create orphans in the same sense as
disposeMCon above, and so returns the number. It really ought to be zero
unless the client has created objects meant to endure until program
termination. Since all types are deactivated the additional step of
deactivating the memory controller itself is taken. All storage used by the
package is returned to the system storage allocator. */
counter disposeAllMCons(void)
{
counter orphans = 0;
MCon bop, bop2;
bop = controlCon->next;
while (bop != controlCon) {
bop2 = bop->next;
orphans += disposeMCon(bop);
bop = bop2;
}
purgeMCon(controlCon);
free((void *) controlCon);
controlCon = (void *) 0; /* de-initialize mc */
return (orphans); /* total number of "orphans", should be 0! */
}
/* Internal Routines */
/* Link a new MCon into the doubly-linked list of all known MCons
the list head and tail is the MCon for MCons, so there is always at least one
item on the list and the first item is always the MCon's MCon */
static void linkIn(MCon theConToAdd)
{
theConToAdd->next = controlCon->next;
theConToAdd->prev = controlCon;
controlCon->next = theConToAdd;
(theConToAdd->next)->prev = theConToAdd;
}
/* Unlink an MCon (called upon destruction of an Mcon */
static void linkOut(MCon theConToDel)
{
(theConToDel->prev)->next = theConToDel->next;
(theConToDel->next)->prev = theConToDel->prev;
}
/* Debugging and Utility Routines */
/* Print a list of known MCons with statistics. Takes a tag to accompany
printout as an argument. */
void debugCon(char *s)
{
MCon bop;
printf("%s", s);
if (!controlCon) {
printf(" -mc is OFF!\n");
return;
}
bop = controlCon;
do {
printCon(bop);
bop = bop->next;
} while (bop != controlCon);
}
/* Print one MCon. Make a quick check on the integrity of the internal
data structure. */
void printCon(MCon theCon)
{
char *freeBop;
int freeCount;
int OK;
freeBop = theCon->freeList;
freeCount = 0;
while (freeBop) {
freeCount++;
freeBop = *((char **) freeBop);
}
OK = freeCount == theCon->nFree;
printf("%lx = %lu\t%ld\t%ld\t%ld\t%lx\t%s\n",
theCon,
theCon->itemSize,
theCon->nGiven,
theCon->nOut,
theCon->nFree,
theCon->freeList,
OK ? "<ok>" : "<NOK>");
}
[LISTING FOUR]
/* Part 1 of torture-test of the memory controller */
# include <stdio.h>
# include <console.h>
void torture(void);
main()
{
int i;
for (i = 0; i < 100; i++)
torture();
}
[LISTING FIVE]
/* Part 2 of torture-test of the memory controller */
# include "mem.h"
# define MAXTYPES 20
# define MAXINSTANCES 500
# define BASESIZE 25
# define MAXEXTRA 25
# define NPASSES 50000
void torture(void);
void error(char *);
void makeNewType(void);
void makeNewObject(void);
void freeSomeObject(void);
int randle(int);
void debugCon(char *);
struct {
MCon mCon;
long theID;
} regType[MAXTYPES];
struct {
void *mObj;
long typeID;
} mBag[MAXINSTANCES];
int nInstances = 0;
int nTypes = 0;
long serialID = 1000;
void torture()
{
counter orphans = 0;
size_t sizeItem;
int typeIdx, objIdx;
int nPotential, nActual;
long tID;
int i, x;
long looper;
char msg[64];
for (looper = 0; looper < NPASSES; looper++) {
if (orphans) error("orphans have been created");
if (!nTypes) {
if (nInstances) error("instances but no active types");
makeNewType();
}
x = randle(10);
switch (x) {
case 0 : /* make a report */
sprintf(msg, "loop %ld : %d instances of %d types\n",
looper,
nInstances,
nTypes);
debugCon(msg);
break;
case 1 : /* register a new type if room */
makeNewType();
break;
case 2 : /* make a new object if room */
makeNewObject();
break;
case 7 : /* make many new objects */
nPotential = ((MAXINSTANCES - nInstances) >> 2) + 7;
nActual = randle(nPotential);
while (nPotential--)
makeNewObject();
break;
case 3 : /* free an object if any exist */
freeSomeObject();
break;
case 8 : /* free many objects */
nPotential = ((MAXINSTANCES - nInstances) >> 3) + 3;
nActual = randle(nPotential);
while (nPotential--)
freeSomeObject();
break;
case 4 : /* purge free list of a type if any exist */
if (nTypes) {
typeIdx = randle(nTypes);
purgeMCon(regType[typeIdx].mCon);
}
break;
case 9 : /* purge a number of free lists */
if (nTypes) {
nActual = randle(nTypes);
for (i = 0; i < nActual; i++) {
typeIdx = randle(nTypes);
purgeMCon(regType[typeIdx].mCon);
}
}
break;
case 5 : /* free all of a registered type if any exist */
if (nTypes) {
typeIdx = randle(nTypes);
tID = regType[typeIdx].theID;
for (i = 0; i < nInstances; )
if (mBag[i].typeID == tID) {
disposeInstance(mBag[i].mObj);
nInstances--;
mBag[i] = mBag[nInstances];
}
else i++;
/* and maybe kill the controllor */
if (randle(13) > 7) {
orphans += disposeMCon(regType[typeIdx].mCon);
nTypes--;
regType[typeIdx] = regType[nTypes];
}
}
break;
case 6 : /* free all instances of all types */
if (randle(20) < 15) break;
for (i = 0; i < nInstances; i++)
disposeInstance(mBag[i].mObj);
nInstances = 0;
/* kill some controllors */
for (i = 0; i < nTypes;)
if (randle(15) > 13) {
orphans += disposeMCon(regType[i].mCon);
nTypes--;
regType[i] = regType[nTypes];
}
else i++;
/* and maybe kill all the rest and shut down! */
if (randle(20) > 17) {
orphans += disposeAllMCons();
nTypes = 0;
}
break;
}
}
printf("\n%ld passes...\n", NPASSES);
}
void makeNewType()
{
MCon tCon;
size_t sizeItem;
if (nTypes < MAXTYPES) {
sizeItem = BASESIZE + randle(MAXEXTRA);
tCon = newMCon(sizeItem);
if (!tCon) {
error("could not make controllor");
return;
}
regType[nTypes].mCon = tCon;
regType[nTypes].theID = serialID++;
nTypes++;
}
}
void makeNewObject()
{
int typeIdx;
void *tObj;
if ((nInstances < MAXINSTANCES) && nTypes) {
typeIdx = randle(nTypes);
tObj = newInstanceOf(regType[typeIdx].mCon);
if (!tObj) {
error("could not get object memory");
return;
}
mBag[nInstances].mObj = tObj;
mBag[nInstances].typeID = regType[typeIdx].theID;
nInstances++;
}
}
void freeSomeObject()
{
int objIdx;
if (nInstances) {
objIdx = randle(nInstances);
disposeInstance(mBag[objIdx].mObj);
nInstances--;
mBag[objIdx] = mBag[nInstances];
}
}
void error(char *s) /* print error message and hang */
{
char hang[12];
printf("\nERROR : %s\n", s);
scanf("%s", hang);
}
randle(int n) /* random number up to not including n */
{
if (n <= 0) error("bogus randle call");
return (rand() % n);
}
[Examplσ 1║ Thσ K&╥ tnodσ allocator]
struct tnode *talloc()
{
char *malloc();
return ((struct tnode *) malloc(sizeof(struct tnode)));
}